<template>
  <div class="pro-iframe-container">
    <iframe ref="iframeRef" v-bind="attrs" :srcdoc="srcdoc" />
  </div>
</template>
<script lang="ts" setup name="ProIframe">
  import { IframeHTMLAttributes, useAttrs } from 'vue'

  // 原生attrs:
  // allow?: string
  // allowfullscreen?: Booleanish
  // allowtransparency?: Booleanish
  // frameborder?: Numberish
  // height?: Numberish
  // marginheight?: Numberish
  // marginwidth?: Numberish
  // name?: string
  // referrerpolicy?: string
  // sandbox?: string
  // scrolling?: string
  // seamless?: Booleanish
  // src?: string
  // srcdoc?: string
  // width?: Numberish

  interface proIframeType {
    // 自适应高度
    adaptionHeight?: boolean
    // 是否隐藏滑轮，在自适应高度=true的情况下无效
    hideScrollBar?: boolean
    // 滑轮宽度，在自适应高度=true的情况下无效
    hideScrollWidth?: string
    // 初始加载开关
    openLoading?: boolean
    // srcdoc
    srcdoc?: string
    minHeight?: string
    src?: string
  }

  const props = withDefaults(defineProps<proIframeType>(), {
    adaptionHeight: true,
    hideScrollBar: true,
    openLoading: true,
    minHeight: '40px'
  })

  // 合并attrs
  const defaultAttrs = {
    frameborder: 0,
    width: '100%'
  }

  const attrs = computed<IframeHTMLAttributes>(() => {
    return {
      ...defaultAttrs,
      ...useAttrs()
    }
  })

  // 隐藏滚动条功能
  const iframeWidth = computed(() => {
    return attrs.value.width
  })

  const scrollWidth = computed(() => {
    const { hideScrollBar, hideScrollWidth } = props
    return hideScrollBar ? hideScrollWidth || '18px' : '0px'
  })

  // 高度自适应功能
  const iframeRef = ref<any>(null)
  const iframeHeight = ref(props.minHeight)

  const updateIframeScroll = () => {
    if (!props.adaptionHeight) return
    const iframeBodyEle =
      iframeRef.value?.contentWindow?.document?.getElementsByTagName('body')[0]
    const iframeHtmlEle =
      iframeRef.value?.contentWindow?.document?.getElementsByTagName('html')[0]
    if (iframeHtmlEle && iframeHtmlEle.style) {
      iframeHtmlEle.style.overflow = 'hidden'
      iframeHtmlEle.style['word-wrap'] = 'break-word'
    }
    if (!iframeBodyEle) return
    const { marginTop, marginBottom } = getComputedStyle(iframeBodyEle)
    iframeHeight.value = `${
      iframeBodyEle.clientHeight +
      Number(marginTop.replace('px', '')) +
      Number(marginBottom.replace('px', ''))
    }px`
  }

  // 根据图片加载情况来渐进式增加高度
  const setImagesLoad = () => {
    const iframeEle = iframeRef.value?.contentWindow
    const imgs = iframeEle?.document?.getElementsByTagName('img') || []
    for (let i = 0; i < imgs.length; i++) {
      if (imgs[i].complete) continue
      imgs[i].style.display = 'none'
      imgs[i].onload = () => {
        imgs[i].style.display = 'block'
        updateIframeScroll()
      }
    }
  }

  watch(
    () => props.srcdoc,
    (srcdoc) => {
      if (srcdoc === '') {
        iframeHeight.value = props.minHeight
        return
      }
      nextTick(() => {
        setTimeout(() => {
          if (!props.adaptionHeight) return
          setImagesLoad()
          updateIframeScroll()
        }, 50)
      })
    }
  )
</script>
<style lang="less" scoped>
  .pro-iframe-container {
    width: v-bind(iframeWidth);
    height: v-bind(iframeHeight);
    overflow: hidden;
    min-height: 40px;
    transition: height 0.3s;
    iframe {
      width: calc(100% + v-bind(scrollWidth));
      height: 100%;
      transition: height 0.3s;
    }
  }
</style>
